
// 这种方式不能形成模块且不能在 原型上添加方法
// import { myCall } from './libs/utils.js'
// myCall();

import utilsModule from './libs/utils.js'
// import utilsModule from './libs/utilsES6.js'

const { typeOf } = utilsModule;

/**
 * call:
 * 1. 一个函数(test) -> call() -> (相当于执行) test()
 * 2. test -> (函数内部的)this -> call的第一个参数
 * 3. call -> 第二个参数开始 -> 为 函数(test) 的参数列表
 */

// function test(ctx) {
  // console.log('ctx:' + ctx);
//   console.log(this, arguments);
// }

// test(123)

// ES6的模块化中 自动使用严格模式
// (use strict)this -> undefined  非严格模式: this -> window
// test();

// function test1() {}

// test.call({
//   a: 1,
//   b: 2
// }, 'c', 'd')
// test.call(test1, 'c', 'd')

// var obj = {
//   a: 1,
//   b: 2,
//   test() {
//     console.log(this);
//   }
// }

// 对于一个方法来说，谁调用它，默认函数内部的this指向就指向谁
// obj.test();

// test() 相等于 window.test()


// function test(ctx) {
  // console.log('ctx:' + ctx);
//   console.log(this, arguments);
//   return 'over';
// }
// function test1() {};

// var obj = {
//   a: 1,
//   b: 2
// }

// var ret = test.call(test1, 'c', 'd');
// console.log(ret)

// console.log('-----------------')

// var ret1 = test.myCall(test1, 'c', 'd');
// console.log(ret1)




// ----------------------------------------------------------




/**
 * apply:
 * 1. test - apply() -> test()
 * 2. apply -> 第二个参数 -> [] -> test 的实参列表
 * 3. apply -> 第二个参数 -> {}\fn -> arguments -> length 0
 * 4. apply -> 只取到第二个参数 -> 第三个参数开始到最后都忽略
 * 5. apply -> 第二个参数 -> null\undefined -> arguments -> length 0
 * 6. apply -> 第二个参数 -> 原始值(数字、字符串) ->
 *  TypeError: CreateListFromArrayLike called on non-object
 * 
 */


// function test() {
//   console.log(this, arguments);
// }
// function test1() {};

// var obj = {
//   a: 1,
//   b: 2
// }

// test.apply(obj, ['c', 'd']);
// test.apply(obj, [3, 4]);
// test.apply(obj, 'c', 'd');
// test.apply(obj, true);
// test.apply(obj, null);
// test.apply(obj, test1);
// test.apply(obj, { a: 'c', b: 'd'});
// test.apply(obj, [1, 2], [3, 4], [5, 6]);

// console.log('-----------------')

// console.log(typeOf(6))

// test.myApply(obj, ['c', 'd']);
// test.myApply(obj, [3, 4]);
// test.myApply(obj, 'c', 'd');
// test.myApply(obj, true);
// test.myApply(obj, null);
// test.myApply(obj, test1);
// test.myApply(obj, { a: 'c', b: 'd'});
// test.myApply(obj, [1, 2], [3, 4], [5, 6]);




// ----------------------------------------------------------




/**
 * bind: 
 * 1. test -> bind() -> test不执行 -> 返回一个新的函数
 * 2. bind -> 第一个参数 -> test -> this -> obj
 * 3. bind可以分离test 的参数
 *    bind 接收一部分参数    返回的新的函数接收一部分参数
 * 4. bind&call的函数参数传递方式是一样的
 * 5. 实例化返回的新函数 -> this指向是test构造出来的实例
 * 6. 实例应该继承test构造函数上的原型
 */

function test(user, car) {
  this.c = 'c';
  console.log(user + '刚买了一辆' + car + '车');
  console.log(this, arguments);
}

var obj = {
  a: 1,
  b: 2
}

test.prototype.myFriend = '李四'

var t = test.bind(obj, '张三')
t('宝马');

var newT = new t();
console.log(newT);
console.log(newT.myFriend);


console.log('-----------------')

function test2(user, car) {
  this.c = 'c';
  console.log(user + '刚买了一辆' + car + '车');
  console.log(this, arguments);
}

var obj2 = {
  a: 1,
  b: 2
}

test2.prototype.myFriend = '李四'

var t2 = test2.myBind(obj2, '张三')
t2('宝马');

var newT2 = new t2();
console.log(newT2);
console.log(newT2.myFriend);
